﻿using System;
using System.ServiceModel;
using SurfaceInteraction.Services.Implementation;
using System.Threading.Tasks;
using SurfaceInteraction.MetaData.ServiceContracts;
using SurfaceInteraction.MetaData;
using System.Windows.Threading;

namespace SurfaceInteraction.UI.Surface.Services
{
    internal class HostService 
    {
        private const string CLASS_NAME = "HostService";
        private static bool __isRemoteDesktopHostInitialized;
        private static object __remoteDesktopHostSync;
        private static ServiceHost __remoteDesktopHost;
        private static RemoteDesktopFrameService __rd;

        private static bool __isFileExchangeHostInitialized;
        private static object __fileExchangeHostSync;
        private static ServiceHost __fileExchangeHost;
        private static FileExchangeService __fe;

        #region ctor
        static HostService()
        {
            __remoteDesktopHostSync = new object();
            __rd = new RemoteDesktopFrameService();
            __isRemoteDesktopHostInitialized = false;

            __fileExchangeHostSync = new object();
            __fe = new FileExchangeService();
            __isFileExchangeHostInitialized = false;
            __fe.DownloadRequestEvent += new MetaData.DownloadRequestEventHandler(__fe_DownloadRequestEvent);
            __fe.UploadRequestEvent += new MetaData.UploadRequestEventHandler(__fe_UploadRequestEvent);
        }
        #endregion

        #region public methods
        public static void StartSerivceHosts()
        {
            if (__isRemoteDesktopHostInitialized == false)
            {
                Task.Factory.StartNew(() => InizializeRemoteDesktopService());
            }

            if (__isFileExchangeHostInitialized == false)
            {
                Task.Factory.StartNew(() => InizializFileExchangeService());
            }
        }

        public static void StopSerivceHosts()
        {
            lock (__remoteDesktopHostSync)
            {
                if (__remoteDesktopHost != null)
                {
                    try
                    {
                        __remoteDesktopHost.Close();
                        __remoteDesktopHost = null;
                        __isRemoteDesktopHostInitialized = false;
                    }
                    catch
                    { }
                }
            }

            lock (__fileExchangeHostSync)
            {
                if (__fileExchangeHost != null)
                {
                    try
                    {
                        __fileExchangeHost.Close();
                        __fileExchangeHost = null;
                        __isFileExchangeHostInitialized = false;
                    }
                    catch
                    { }
                }
            }
        }

        public static void SetFrame(SurfaceFrame frame)
        {
            if (__isRemoteDesktopHostInitialized == false)
            {
                Task.Factory.StartNew(() => InizializeRemoteDesktopService());
            }

            DateTime dt = DateTime.Now;
            while (__isRemoteDesktopHostInitialized == false && dt.AddSeconds(Constants.HOST_METHODS_TIMEOUT) > DateTime.Now)
            { 
                // wait for service initialization
            }

            if (__isRemoteDesktopHostInitialized == true)
                __rd.SetFrame(frame);
        }

        public static void SendImage(Guid imageId, byte[] image)
        {
            if (__isFileExchangeHostInitialized == false)
            {
                Task.Factory.StartNew(() => InizializFileExchangeService());
            }

            DateTime dt = DateTime.Now;
            while (__isFileExchangeHostInitialized == false && dt.AddSeconds(Constants.HOST_METHODS_TIMEOUT) > DateTime.Now)
            {
                // wait for service initialization
            }

            // some really talented guy seeing this code said me: "yes, but this never throw exceprtion"
            // and I replied yes! Because in production my goal is that you can change IP, binding (in te congig) and 
            // this have to try with the new config without restarting. There is some effert but all robust code needs effort.

            if (__isFileExchangeHostInitialized == true)
                __fe.SendImage(imageId, image);
        }
        #endregion

        #region private methods
        private static void InizializeRemoteDesktopService()
        {
            const string METHOD_NAME = "InizializeRemoteDesktopService";

            if (__isRemoteDesktopHostInitialized == false)
            {
                lock (__remoteDesktopHostSync)
                {
                    // double check __isRemoteDesktopHostInitialized == false to prevent concurrency
                    if (__isRemoteDesktopHostInitialized == false)
                    {
                        try
                        {
                            //Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal,
                            //(System.Action)(() =>
                            //{
                            //    LogHelper.Writer.Write(string.Format("Starting Apllication class: {0}, method: {1}", CLASS_NAME, METHOD_NAME), Category.General, Priority.Normal);
                            //}));
                            __remoteDesktopHost = new System.ServiceModel.ServiceHost(__rd, new Uri(Constants.REMOTE_DESKTOP_SERVICE_URI));
                            __remoteDesktopHost.Open();
                            __isRemoteDesktopHostInitialized = true;
                            //Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal,
                            //(System.Action)(() =>
                            //{
                            //LogHelper.Writer.Write(string.Format("Ending Apllication class: {0}, method: {1}", CLASS_NAME, METHOD_NAME), Category.General, Priority.Normal);
                            //    }));
                        }
                        catch (Exception ex)
                        {
                            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal,
                            (System.Action)(() =>
                            {
                            //LogHelper.Writer.Write(string.Format("Ending Apllication class: {0}, method: {1} - Error{2}", CLASS_NAME, METHOD_NAME, ex.Message), Category.Trace, Priority.High);
                            __isRemoteDesktopHostInitialized = false;
                            }));
                            if (__remoteDesktopHost != null)
                            {
                                try
                                {
                                    __remoteDesktopHost.Abort();
                                    __remoteDesktopHost = null;
                                }
                                catch
                                { }
                            }
                        }
                    }
                }
            }
        }

        private static void InizializFileExchangeService()
        {
            if (__isFileExchangeHostInitialized == false)
            {
                lock (__fileExchangeHostSync)
                {
                    // double check __isRemoteDesktopHostInitialized == false to prevent concurrency
                    if (__isFileExchangeHostInitialized == false)
                    {
                        __isFileExchangeHostInitialized = true;

                        try
                        {
                            __fileExchangeHost = new System.ServiceModel.ServiceHost(__fe, new Uri(Constants.FILE_EXCHANGE_SERVICE_URI));
                            __fileExchangeHost.Open();
                        }
                        catch
                        {
                            __isFileExchangeHostInitialized = false;
                            if (__fileExchangeHost != null)
                            {
                                try
                                {
                                    __fileExchangeHost.Abort();
                                    __fileExchangeHost = null;
                                }
                                catch
                                { }
                            }
                        }
                    }
                }
            }
        }
        #endregion

        #region File Exchange Events
        public static event UploadRequestEventHandler UploadRequestEvent;
        public static event DownloadRequestEventHandler DownloadRequestEvent;

        private static void __fe_UploadRequestEvent(object sender, FileExchangeRequestEventArgs e)
        {
            var handler = UploadRequestEvent;
            if (handler != null)
            {
                handler(sender, e);
            }
        }

        private static void __fe_DownloadRequestEvent(object sender, MetaData.FileExchangeRequestEventArgs e)
        {
            var handler = DownloadRequestEvent;
            if (handler != null)
            {
                handler(sender, e);
            }
        }
        #endregion
    }
}
